<?php

namespace think\jwt;

use Exception;
use Lcobucci\JWT\Token;
use think\jwt\exception\InvalidArgumentException;
use think\jwt\interfaces\AuthorizationUserInterface;

class JwtAuth
{
    /**
     * @var Config
     */
    protected Config $config;

    /**
     * @var Jwt
     */
    protected Jwt $jwt;

    /**
     * @var Event
     */
    protected mixed $event;

    /**
     * @var User
     */
    protected User $user;

    public function __construct()
    {
        $this->config = new Config(config('jwt'));
        if ($this->config->getEventHandler()) {
            $eventHandler = $this->config->getEventHandler();
            $this->event = new $eventHandler();
        } else {
            $this->event = false;
        }

        $this->init();
    }

    protected function init()
    {
        $this->jwt = new Jwt($this);

        $this->initUser();
    }

    protected function initUser()
    {
        if ($model = $this->config->getUserModel()) {
            $this->user = new User($model);
        }
    }

    /**
     * 获取 Token 配置
     */
    public function getConfig(): Config
    {
        return $this->config;
    }

    /**
     * 生成 Token
     * @param int|string $id 唯一标识
     * @param array $claims 附带参数
     *
     * @return Token
     */
    public function token(int|string $id, array $claims = []): Token
    {
        $token = $this->jwt->make($id, $claims);

        if ($this->event) {
            $this->event->login($token);
        }
        return $token;
    }

    /**
     * 检测合法性
     * @param string $token
     * @return bool
     */
    public function verify(string $token): bool
    {
        $flag = $this->jwt->validate($token);
        if ($this->event) {
            $this->event->verify($this->parseToken($token));
        }
        return $flag;
    }

    /**
     * 解析 Token
     * @param string $token jwt token
     * @return Token
     */
    public function parseToken(string $token): Token
    {
        return $this->jwt->parseToken($token);
    }

    /**
     * 获取验证后的Token对象
     * @return Token
     * @throws Exception
     */
    public function getVerifyToken(): Token
    {
        return $this->jwt->getVerifyToken();
    }

    /**
     * 获取登录用户对象
     *
     * @return AuthorizationUserInterface|null
     * @throws Exception
     */
    public function getUser(): ?AuthorizationUserInterface
    {
        if ($this->user) {
            return $this->user->get($this->jwt);
        }
        throw new InvalidArgumentException('jwt.user_model required');
    }
}